﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NZBMatrixAdvancedFeedReader.Classes
{
    class FeedLoader
    {

        #region Events

        public delegate void dlgProgressChanged(int percentage);
        
        /// <summary>
        /// This event helps to trace the progress of search.
        /// </summary>
        public dlgProgressChanged ProcessChanged;

        #endregion

        #region Properties

        /// <summary>
        /// Current Search Template used for searching.
        /// </summary>
        public SearchTemplate SearchTemplate { get; set; }

        #endregion

        #region Public Methods

        /// <summary>
        /// Reads the NZBMatrix feed and parse and filters the result into the MovieFeed objects.
        /// </summary>
        /// <returns></returns>
        public List<MovieFeed> LoadFeeds()
        {

            string searchURL;
            string feedXML;
            List<MovieFeed> feedList;

            //  Register MovieFeed Progress Event.
            MovieFeed.ProcessChanged += MovieFeed_ProcessChanged;

            InvokeProcessChanged(0);
            //  Prepare Searching Query
            CommonTasks.WriteLog("Preparing Searching Query...");
            searchURL = BuildNZBMatrixSearchURL();

            InvokeProcessChanged(1);

            //  Read URL into a XML string.
            CommonTasks.WriteLog("Reading URL into a XML string....");
            feedXML = CommonTasks.ReadURLToString(searchURL);
            //feedXML = System.IO.File.ReadAllText(@"D:\sample.xml");
            InvokeProcessChanged(5);

            //  Extract Movie information   
            CommonTasks.WriteLog("Extracting Movie information ...");
            feedList = MovieFeed.FromXML(feedXML);

            InvokeProcessChanged(95);

            //  Filter list by Rate and Yesr
            CommonTasks.WriteLog("Filtering for Movie Year and Rate ... ");
            feedList = FilterByYearRate(feedList);

            //  Sort by title
            feedList = feedList.OrderBy(x => x.Title).ToList();

            InvokeProcessChanged(100);

            CommonTasks.WriteLog("Result are ready.");

            return feedList;

        }


        #endregion

        #region Event Handlers

        /// <summary>
        /// Handles the ProcessChanged event from the MovieFeed XML Parser and inform UI from the changes.
        /// </summary>
        /// <param name="percentage"></param>
        private void MovieFeed_ProcessChanged(int percentage)
        {
            InvokeProcessChanged(5 + (percentage * 90 / 100));
        }

        #endregion

        #region Private Methods
        
        /// <summary>
        /// Apply filter on MovieFeed List base on the Release Year and Rate of the Movie.
        /// </summary>
        /// <param name="feedList"></param>
        /// <returns></returns>
        private List<MovieFeed> FilterByYearRate(List<MovieFeed> feedList)
        {

            return feedList.Where(f => (!SearchTemplate.HasMovieYearLimit || (string.Compare(f.MovieYear, SearchTemplate.MovieYearFrom) >= 0 && string.Compare(f.MovieYear, SearchTemplate.MovieYearTo) <= 0))
                                    && (!SearchTemplate.HasMovieRateLimit || (double.Parse(f.MovieRate) >= double.Parse(SearchTemplate.MovieRateFrom) && double.Parse(f.MovieRate) <= double.Parse(SearchTemplate.MovieRateTo)))).ToList();

        }

        /// <summary>
        /// Build search parameters for the URL which used to call NZBMatrix website.
        /// </summary>
        /// <returns></returns>
        private string BuildNZBMatrixSearchURL()
        {
            //("http://rss.nzbmatrix.com/rss.php?page=details&subcat=42&english=1&maxage=1700"
            List<string> parameters;
            StringBuilder sbURL;

            parameters = new List<string>();
            sbURL = new StringBuilder();


            if (SearchTemplate.UseSSL)
            {
                sbURL.Append("http://rss.nzbmatrix.com/rss.php?");
                parameters.Add("ssl=1");
            }
            else
                sbURL.Append("https://rss.nzbmatrix.com/rss.php?");

            parameters.Add("subcat=" + SearchTemplate.Categories);

            if (SearchTemplate.EnglishOnly)
                parameters.Add("english=1");

            switch (SearchTemplate.LinkType)
            {
                case SearchTemplate.LinkTypes.NZBLinkDetailsLink:
                    parameters.Add("page=details");
                    break;
                case SearchTemplate.LinkTypes.NZBDownloadLink:
                    parameters.Add("page=download");
                    parameters.Add("username=" + SystemSettings.NZBMatrix.UserName);
                    parameters.Add("apikey=" + SystemSettings.NZBMatrix.APIKey);
                    break;
                default:
                    break;
            }

            if (SearchTemplate.PreserveFileName)
                parameters.Add("scenename=1");

            if (SystemSettings.MaxPostAge > 0)
                parameters.Add("maxage=" + SystemSettings.MaxPostAge.ToString());

            if (!string.IsNullOrEmpty(SearchTemplate.SearchTerm))
                parameters.Add("term=" + SearchTemplate.SearchTerm);

            switch (SearchTemplate.SearchMethod)
            {
                case SearchTemplate.SearchMethods.UsenetPostSubject:
                    parameters.Add("searchin=subject");
                    break;
                case SearchTemplate.SearchMethods.Weblink:
                    parameters.Add("searchin=weblink");
                    break;
                default:
                    break;
            }

            sbURL.Append(parameters.Aggregate((current, next) => (current + "&" + next)));

            return sbURL.ToString();

        }

        private void InvokeProcessChanged(int percentage)
        {
            if (ProcessChanged != null)
                ProcessChanged(percentage);
        }

        #endregion

    }
}
